///*
// * Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// *     http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//package com.letu.core.snowflake;
//
//import cn.hutool.core.date.DatePattern;
//import cn.hutool.core.date.DateUtil;
//import cn.hutool.core.util.StrUtil;
//import com.letu.core.context.ContextConstants;
//import com.letu.uid.util.BitsAllocator2;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.InitializingBean;
//
//import java.util.ArrayList;
//import java.util.Date;
//import java.util.List;
//import java.util.concurrent.TimeUnit;
//
///**
// * Represents an implementation of {@link }
// * <p>
// * The unique id has 64bits (long), default allocated as blow:<br>
// * <li>sign: The highest bit is 0
// * <li>delta seconds: The next 28 bits, represents delta seconds since a customer epoch(2016-05-20 00:00:00.000).
// * Supports about 8.7 years until to 2024-11-20 21:24:16
// * <li>worker id: The next 22 bits, represents the worker's id which assigns based on database, max id is about 420W
// * <li>sequence: The next 13 bits, represents a sequence within the same second, max for 8192/s<br><br>
// * <p>
// * The {@link DefaultUidGenerator#parseUid(long)} is a tool method to parse the bits
// *
// * <pre>{@code
// * +------+----------------------+----------------+-----------+
// * | sign |     delta seconds    | worker node id | sequence  |
// * +------+----------------------+----------------+-----------+
// *   1bit          28bits              22bits         13bits
// * }</pre>
// * <p>
// * You can also specified the bits by Spring property setting.
// * <li>timeBits: default as 28
// * <li>workerBits: default as 22
// * <li>seqBits: default as 13
// * <li>epochStr: Epoch date string format 'yyyy-MM-dd'. Default as '2016-05-20'<p>
// *
// * <b>Note that:</b> The total bits must be 64 -1
// *
// * @author yutianbao
// */
//public class DefaultUidGenerator {
//    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultUidGenerator.class);
//
//    static long epochSeconds = TimeUnit.MILLISECONDS.toSeconds(1600012800000L);
//    /**
//     * Stable fields after spring bean initializing
//     */
//    static BitsAllocator2 bitsAllocator;
//    static long workerId;
//    /**
//     * Bits allocate
//     */
//    private static int timeBits = 28;
//    private static int workerBits = 17;
//    private static int buinessBits = 6;
//    private static int seqBits = 12;
//
//    /**
//     * Volatile fields caused by nextId()
//     */
//    private static long sequence = 0L;
//    private static long lastSecond = -1L;
//    /**
//     * 上次生成ID的时间截
//     */
//    private static long lastTimestamp = 1600012800000L;
//
//    static {
//        // initialize bits allocator
//        bitsAllocator = new BitsAllocator2(timeBits, workerBits, buinessBits, seqBits);
//
//        // initialize worker id
//        workerId = ContextConstants.WORK_ID;
//        if (workerId > bitsAllocator.getMaxWorkerId()) {
//            throw new RuntimeException("Worker id " + workerId + " exceeds the max " + bitsAllocator.getMaxWorkerId());
//        }
//        LOGGER.info("Initialized bits(1, {}, {}, {}) for workerID:{}", timeBits, workerBits, seqBits, workerId);
//    }
//
//    public static long getUidOfProjectId(Long projectId) {
//        try {
//            return nextId(parseUid(projectId));
//        } catch (Exception e) {
//            LOGGER.error("Generate unique id exception. ", e);
//            e.printStackTrace();
//        }
//        return 0L;
//    }
//
//    /**
//     * 批量生成uid
//     * @param projectId
//     * @param size
//     * @return
//     */
//    public static List<Long> getBatUidOfProjectId(Long projectId, int size) {
//        try {
//            List<Long> longs = new ArrayList<>();
//            for(int i=0;i<size;i++){
//                longs.add(nextId(parseUid(projectId)));
//            }
//            return longs;
//        } catch (Exception e) {
//            LOGGER.error("Generate unique id exception. ", e);
//            e.printStackTrace();
//        }
//        return null;
//    }
//
//    public static long getUid(Long buinsessId) {
//        try {
//            return nextId(buinsessId);
//        } catch (Exception e) {
//            LOGGER.error("Generate unique id exception. ", e);
//            e.printStackTrace();
//        }
//        return 0L;
//    }
//
//    public static long parseUid(long uid) {
//        long totalBits = BitsAllocator2.TOTAL_BITS;
//        long signBits = bitsAllocator.getSignBits();
//        long timestampBits = bitsAllocator.getTimestampBits();
//        long workerIdBits = bitsAllocator.getWorkerIdBits();
//        long buinessIdBits = bitsAllocator.getBuinessIdBits();
//
//        long sequenceBits = bitsAllocator.getSequenceBits();
//        // parse UID
//        final long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);
//        final long workerId = (uid << (timestampBits + signBits)) >>> (totalBits - workerIdBits);
//        final long buinessId = (uid << (timestampBits + signBits + workerIdBits)) >>> (totalBits - buinessIdBits);
//        final long deltaSeconds = uid >>> (workerIdBits + sequenceBits);
//        Date thatTime = new Date(TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(lastTimestamp) + deltaSeconds));
//        String thatTimeStr = DateUtil.format(thatTime, DatePattern.NORM_DATETIME_PATTERN);
//        // format as string //delta seconds    | worker node id | sequence
////        return String.format("{\"UID\":\"%d\",\"timestamp\":\"%s\",\"workerId\":\"%d\",\"buinessId\":\"%d\",\"sequence\":\"%d\"}",
////                uid, thatTimeStr, workerId,buinessId, sequence);
//        return buinessId;
//    }
//
//
//    protected static synchronized long nextIdOfProjectId(Long projectId) throws Exception {
//        Long buinessId = parseUid(projectId);
//        return nextId(buinessId);
//    }
//
//
//    protected static synchronized long nextId(Long buinsessId) throws Exception {
//        long currentSecond = getCurrentSecond();
//
//        // Clock moved backwards, refuse to generate uid
//        if (currentSecond < lastSecond) {
//            long refusedSeconds = lastSecond - currentSecond;
//            throw new Exception("Clock moved backwards. Refusing for %d seconds");
//        }
//
//        // At the same second, increase sequence
//        //同一秒内的，本次发号请求不是本秒的第一次, sequence 加一
//        if (currentSecond == lastSecond) {
//            sequence = (sequence + 1) & bitsAllocator.getMaxSequence();
//            // Exceed the max sequence, we wait the next second to generate uid
//            // 号发完了，等到下一秒
//            if (sequence == 0) {
//                currentSecond = getNextSecond(lastSecond);
//            }
//
//            // At the different second, sequence restart from zero
//        } else {
//            //新的一秒，重新开始发号
//            sequence = 0L;
//        }
//
//        lastSecond = currentSecond;
//
//        // Allocate bits for UID
//        return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, buinsessId, sequence);
//    }
//
//    /**
//     * Get next millisecond
//     */
//    private static long getNextSecond(long lastTimestamp) throws Exception {
//        long timestamp = getCurrentSecond();
//        while (timestamp <= lastTimestamp) {
//            timestamp = getCurrentSecond();
//        }
//
//        return timestamp;
//    }
//
//    /**
//     * Get current second
//     */
//    private static long getCurrentSecond() throws Exception {
//        long currentSecond = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
//        if (currentSecond - epochSeconds > bitsAllocator.getMaxDeltaSeconds()) {
//            throw new Exception("Timestamp bits is exhausted. Refusing UID generate. Now: " + currentSecond);
//        }
//
//        return currentSecond;
//    }
//
//    public void setTimeBits(final int timeBits) {
//        if (timeBits > 0) {
//            this.timeBits = timeBits;
//        }
//    }
//
//    public void setWorkerBits(int workerBits) {
//        if (workerBits > 0) {
//            this.workerBits = workerBits;
//        }
//    }
//
//    public void setSeqBits(int seqBits) {
//        if (seqBits > 0) {
//            this.seqBits = seqBits;
//        }
//    }
//
//    public static void main(String[] args) {
//       long i = parseUid(1840123865955831808L);
//        System.out.println("解析的库名："+i);
//    }
//
//}
